From 7186363e849b774022d769f1a88a14909a4fc11b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 14 Nov 2006 17:00:05 +0000 Subject: [PATCH] [LINUX] x86/64: Fix backward compatibility to Xen 3.0.2. This requires us to explicitly specify _PAGE_USER for kernel mappings. Original patch by Jan Beulich and Gerd Hoffmann. Signed-off-by: Keir Fraser --- .../arch/i386/mm/ioremap-xen.c | 2 +- .../arch/x86_64/mm/init-xen.c | 32 +++++++++++++++++++ .../include/asm-x86_64/mach-xen/asm/pgtable.h | 19 +++++++---- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c index 640c74d67c..b2e8832b85 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c @@ -249,7 +249,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l return NULL; area->phys_addr = phys_addr; addr = (void __iomem *) area->addr; - flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; + flags |= _KERNPG_TABLE; if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr, phys_addr>>PAGE_SHIFT, size, __pgprot(flags), domid)) { diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c index 455b20b47e..032c31e532 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c @@ -56,6 +56,11 @@ struct dma_mapping_ops* dma_ops; EXPORT_SYMBOL(dma_ops); +#ifdef CONFIG_XEN_COMPAT_030002 +unsigned int __kernel_page_user; +EXPORT_SYMBOL(__kernel_page_user); +#endif + extern unsigned long *contiguous_bitmap; static unsigned long dma_reserve __initdata; @@ -527,6 +532,33 @@ void __init xen_init_pt(void) addr = page[pud_index(__START_KERNEL_map)]; addr_to_page(addr, page); +#ifdef CONFIG_XEN_COMPAT_030002 + /* On Xen 3.0.2 and older we may need to explicitly specify _PAGE_USER + in kernel PTEs. We check that here. */ + if (HYPERVISOR_xen_version(XENVER_version, NULL) <= 0x30000) { + unsigned long *pg; + pte_t pte; + + /* Mess with the initial mapping of page 0. It's not needed. */ + BUILD_BUG_ON(__START_KERNEL <= __START_KERNEL_map); + addr = page[pmd_index(__START_KERNEL_map)]; + addr_to_page(addr, pg); + pte.pte = pg[pte_index(__START_KERNEL_map)]; + BUG_ON(!(pte.pte & _PAGE_PRESENT)); + + /* If _PAGE_USER isn't set, we obviously do not need it. */ + if (pte.pte & _PAGE_USER) { + /* _PAGE_USER is needed, but is it set implicitly? */ + pte.pte &= ~_PAGE_USER; + if ((HYPERVISOR_update_va_mapping(__START_KERNEL_map, + pte, 0) != 0) || + !(pg[pte_index(__START_KERNEL_map)] & _PAGE_USER)) + /* We need to explicitly specify _PAGE_USER. */ + __kernel_page_user = _PAGE_USER; + } + } +#endif + /* Construct mapping of initial pte page in our own directories. */ init_level4_pgt[pgd_index(__START_KERNEL_map)] = mk_kernel_pgd(__pa_symbol(level3_kernel_pgt)); diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h index ff6d94f9e0..0c4d0a888e 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h @@ -205,8 +205,14 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long #define _PAGE_PROTNONE 0x080 /* If not present */ #define _PAGE_NX (1UL<<_PAGE_BIT_NX) +#ifdef CONFIG_XEN_COMPAT_030002 +extern unsigned int __kernel_page_user; +#else +#define __kernel_page_user 0 +#endif + #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user) #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) @@ -219,13 +225,13 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define __PAGE_KERNEL \ - (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) #define __PAGE_KERNEL_EXEC \ - (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | __kernel_page_user) #define __PAGE_KERNEL_NOCACHE \ - (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) #define __PAGE_KERNEL_RO \ - (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) + (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) #define __PAGE_KERNEL_VSYSCALL \ (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define __PAGE_KERNEL_VSYSCALL_NOCACHE \ @@ -422,7 +428,8 @@ static inline pud_t *pud_offset_k(pgd_t *pgd, unsigned long address) can temporarily clear it. */ #define pmd_present(x) (pmd_val(x)) #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) -#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT)) +#define pmd_bad(x) ((pmd_val(x) & ~(PTE_MASK | _PAGE_USER | _PAGE_PRESENT)) \ + != (_KERNPG_TABLE & ~(_PAGE_USER | _PAGE_PRESENT))) #define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot))) #define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT) -- 2.30.2